<?php

namespace App\Library\Logic;

use App\Library\Requests\Product\ProductAddRequest;
use App\Library\Requests\Product\ProductBuyWillSpecsListRequest;
use App\Library\Requests\ShopProductSpec\ShopProductSpecAddRequest;
use App\Library\Requests\ShopProductSpec\ShopProductSpecEditRequest;
use App\Library\Requests\ShopProductSpec\ShopProductSpecPageRequest;
use App\Models\ShopProductSpecsModel;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class ShopProductSpecsLogic extends ShopProductSpecsModel
{
    /**
     * 分页
     * @param ShopProductSpecPageRequest $request
     * @return array
     */
    public function paging(ShopProductSpecPageRequest $request): array
    {
        return paginate(helpBuilder($this->newQuery()->where('user_id', MAINID)
            ->where('ps_is_delete', 2)->orderByDesc('ps_id'), $request)->paginate($request->limit));
    }

    /**
     * add
     * @param ShopProductSpecAddRequest $request
     * @return array
     */
    public function add(ShopProductSpecAddRequest $request): array
    {
        $request->offsetUnset('productNumber');
        $model = self::insertForModel(array_merge(handleRequest($request), $this->saveCom($request), [
            'psTotalStock' => $request->psUsableStock,
        ]));
        cache(['shopProductSpec:' . $model->serial_number => $model->ps_id]);
        OperateLogLogic::add(USERID);
        return [
            'id' => $model->ps_id,
            'serialNumber' => $model->serial_number,
        ];
    }

    /**
     * edit
     * @param ShopProductSpecEditRequest $request
     * @param Model $model
     * @return void
     */
    public function edit(ShopProductSpecEditRequest $request, Model $model): void
    {
        $arr = handleRequest($request);
        if (isset($arr['commission']) && !isset($arr['commissionRatio'])) $arr['commissionRatio'] = 0;
        if (!isset($arr['commission']) && isset($arr['commissionRatio'])) $arr['commission'] = 0;
        else if (!isset($arr['commission']) && !isset($arr['commissionRatio'])) {
            $arr['commissionRatio'] = 0;
            $arr['commission'] = 0;
        }
        self::updateForModel(array_merge($arr, $this->saveCom($request), [
            'psPrice' => $request->psPrice,
            'buyWillPrice' => $request->buyWillPrice,
            'psTotalStock' => $request->psUsableStock + $model->ps_disable_stock,
        ]), $model);
        OperateLogLogic::add(USERID);
    }

    public function checkRepeat(int $productId, string $randProductId, string $psName, ?int $psId = null): bool
    {
        if ($productId > 0) {
            $query = self::query()->where(function ($query) use ($psName, $productId, $randProductId) {
                $query->where('user_id', MAINID)->where('ps_name', $psName);
                $query->where(function ($query) use ($productId, $randProductId) {
                    $query->where('product_id', $productId)->orWhere('rand_product_id', $randProductId);
                });
            });
            if (!is_null($psId)) $query->where('ps_id', '<>', $psId);
            return $query->where('ps_is_delete', 2)->exists();
        } else {
            $where = ['userId' => MAINID, 'psName' => $psName, 'randProductId' => $randProductId, 'psIsDelete' => 2];
            if (!is_null($psId)) $where['psId'] = ['<>', $psId];
            return self::existsByWhere($where);
        }
    }

    /**
     * saveCom
     * @param ShopProductSpecAddRequest $request
     * @return array
     */
    private function saveCom(ShopProductSpecAddRequest $request): array
    {
        $array = ['userId' => MAINID];
        if (!is_null($request->imgId)) {
            $imgUrl = ShopImagesLogic::valueByWhere([
                'imgId' => $request->imgId,
                'userMainId' => MAINID,
                'imgSourceType' => 3,
            ], null, 'imgUrl');
            if (!is_null($imgUrl)) $array = ['psAvatar' => $imgUrl, 'psAvatarImgId' => $request->imgId];
        }
        return $array;
    }

    /**
     * bind
     * @param Model $shopProduct
     * @return void
     */
    public static function bind(Model $shopProduct): void
    {
        if (!is_null($shopProduct->spec_json) && time() > PHP_INT_MAX) {
            $psIdJson = [];
            foreach ($shopProduct->spec_json as $k => $v) {
                $self = self::findBySerialNumber($v);
                if (is_null($self)) continue;
                $psIdJson[] = $self->ps_id;
                self::editSelf($self, $shopProduct, $k);
            }
            $shopProduct->ps_id_json = empty($psIdJson) ? null : json_encode($psIdJson);
        } else {
            if (is_array($shopProduct->ps_id_json)) $psIdJson = $shopProduct->ps_id_json;
            else if (is_string($shopProduct->ps_id_json)) $psIdJson = json_decode($shopProduct->ps_id_json, true);
            else $psIdJson = null;
            if (empty($psIdJson)) return;
            $specJson = [];
            foreach ($psIdJson as $k => $v) {
                $self = self::detail($v);
                if (is_null($self)) continue;
                self::editSelf($self, $shopProduct, $k);
                $specJson[] = $self->serial_number;
            }
            $shopProduct->spec_json = empty($specJson) ? null : $specJson;
        }
        $shopProduct->save();
    }

    /**
     * minPrice
     * @param Model $model
     * @return float
     */
    public static function minPrice(Model $model): float
    {
        $list = self::query()->where('product_id', $model->product_id)->get(['ps_price', 'ps_price_underlined']);
        $start = now()->gt(now()->timestamp($model->product_special_start_time));
        $end = now()->lt(now()->timestamp($model->product_special_end_time));
        $bool = $start && $end;
        $price = PHP_INT_MAX;
        foreach ($list as $v) {
            if ($bool && (float)$v->ps_price > 0) $price = $price > $v->ps_price ? $v->ps_price : $price;
            else $price = $price > $v->ps_price_underlined ? $v->ps_price_underlined : $price;
        }
        return (float)$price;
    }

    public static function checkSave(ProductAddRequest $request): bool
    {
        if (is_null($request->specJson)) return true;
        $pluck = self::query()->whereIn('serial_number', $request->specJson)->pluck('ps_id');
        if (is_null($pluck)) return true;
        else if ($pluck->count() !== count($request->specJson)) return true;
        //request()->offsetSet('psIdJson', json_encode($pluck->toArray()));
        return false;
    }

    /**
     * unsetSpec
     * @param Model $self
     * @return void
     */
    public static function unsetSpec(Model $self): void
    {
        unsetObject($self, [
            'ps_id',
            'serial_number',
            'product_id',
            'user_id',
            'ps_total_stock',
            'ps_disable_stock',
            'sales',
            'created_at',
            'updated_at',
            'deleted_at',
        ]);
    }

    /**
     * editSelf
     * @param Model $self
     * @param Model $shopProduct
     * @param int $k
     * @return void
     */
    public static function editSelf(Model $self, Model $shopProduct, int $k): void
    {
        $self->ps_sort = $k;
        $self->ps_is_delete = 2;
        $self->rand_product_id = 0;
        $self->user_id = $shopProduct->user_id;
        $self->product_id = $shopProduct->product_id;
        $self->save();
    }

    /**
     *
     * @param ProductBuyWillSpecsListRequest $request
     * @return Collection|array
     *
     */
    public static function buyWillSpecsList(ProductBuyWillSpecsListRequest $request): Collection|array
    {
        return self::query()
            ->where('product_id', $request->productId)
            ->where('buy_will_price', '>', 0)
            ->where(function (Builder $builder) {
                $builder->where('ps_buy_limit', 0);
            })->orWhere(function (Builder $builder) use ($request) {
                $builder->where('product_id', $request->productId)->where('ps_buy_limit', '>', DB::raw('
                (SELECT COUNT(*) FROM `shop_order_goods` LEFT JOIN `shop_order` ON `shop_order`.`order_id` = `shop_order_goods`.`order_id`
                    LEFT JOIN `shop_product_specs` ON `shop_order_goods`.`spec_id` = `shop_product_specs`.`ps_id`
                                WHERE `shop_order`.`buy_user_id` = ' . USERID . ' AND `shop_product_specs`.`product_id` = ' . $request->productId . ')
                '));
            })
            ->orderByDesc('ps_id')->get([
                'serial_number',
                'ps_id',
                'product_id',
                'ps_name',
                'ps_avatar',
                'ps_price_underlined',
                'buy_will_price',
                'ps_usable_stock'
            ]);
    }

    public static function plugCheck(string $str): ?string
    {
        $arr = explode(',', $str);
        $list = self::query()->whereIn('serial_number', $arr)->get(['ps_name', 'ps_price', 'ps_total_stock']);
        if ($list->count() != count($arr)) return '规格数据异常,请刷新页面';
        foreach ($list as $v) {
            if (is_null($v->ps_price)) return '规格`' . $v->ps_name . '`价格不能为空';
            else if ($v->ps_price <= 0) return '规格`' . $v->ps_name . '`价格为0';
            else if ($v->ps_total_stock !== 1) return '规格`' . $v->ps_name . '`库存应该为1';
        }
        return null;
    }
}
